package com.cit.servlet;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.soap.SOAPBody;

import org.w3c.dom.Document;

import com.cit.manager.CITWsManager;
import com.cit.service.SoapService;
import com.cit.service.ValidateService;
import com.cit.util.FileUtil;
import com.cit.util.ResponseUtil;

/**
 * 
 * @author Lang Yu(lang.yu@hp.com)
 * @time Mar 8, 2011 10:56:58 PM
 * @file BaseServlet.java
 * @package com.cit.servlet
 * @version 1.0
 * @seen This servlet is
 */
public class BaseServlet extends HttpServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = -8003099779210409859L;

	private ValidateService vService = CITWsManager.newValidator();
	private SoapService sService = CITWsManager.newSoapService();
	private Logger logger = null;
	private FileHandler fileHandler = null;

	/**
	 * Check the root path
	 * 
	 * @param subFolderName
	 * @return
	 */
	private String getFolderPath(String subFolderName) {
		StringBuilder builder = new StringBuilder();
		File file = new File(this.getServletContext().getInitParameter(
				"RootPath"));
		if (file.isDirectory() && file.exists()) {
			builder.append(file.getAbsolutePath());
			builder.append("\\");
			builder.append(this.getServletContext().getInitParameter(
					"CEWSRootFolder"));
			builder.append("\\");
			builder.append(this.getServletContext().getInitParameter(
					subFolderName));
			builder.append("\\");
		}
		return builder.toString();
	}

	/**
	 * Get logger
	 * 
	 * @param filePath
	 * @return
	 */
	private void initLogger(String filePath) {
		try {
			// logManager.readConfiguration(this.getServletContext().getResourceAsStream("/WEB-INF/log.properties"));
			logger = Logger.getLogger(BaseServlet.class.getName());
			fileHandler = new FileHandler(filePath, true);
			fileHandler.setLevel(Level.INFO);
			fileHandler.setFormatter(new SimpleFormatter());
			logger.addHandler(fileHandler);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private void processLogger(Date timeStamp, String message) {
		boolean isLog = Boolean.parseBoolean(this.getServletContext()
				.getInitParameter("IsLog"));
		if (isLog) {
			DateFormat format = new SimpleDateFormat("yyyy_MM_dd");
			String filePath = this.getFolderPath("LogsFolder")
					+ this.getServletContext().getInitParameter("ContextName")
					+ "-" + format.format(timeStamp) + ".log";
			this.initLogger(filePath);
			logger.log(Level.SEVERE, message);
			fileHandler.flush();
			fileHandler.close();
		}
	}

	/**
	 * 主要的执行请求响应的方法
	 * 
	 * @param request
	 * @param response
	 * @param servletType
	 * @throws IOException
	 */
	protected void processRequest(HttpServletRequest request,
			HttpServletResponse response, String servletType)
			throws IOException {
		Date timeStamp = new Date();
		/**
		 * Initialize the folder create process
		 */
		if (this.getServletContext().getInitParameter("RootPath") != null) {
			String[] folders = new String[] { this.getFolderPath("LogsFolder"),
					this.getFolderPath("RawSoapFolder"),
					this.getFolderPath("RawSoapFolder") + servletType + "\\",
					this.getFolderPath("XMLOutputFolder"),
					this.getFolderPath("XMLOutputFolder") + servletType + "\\",
					this.getFolderPath("RequestRulesFolder"),
					this.getFolderPath("ResponseRulesFolder"),
					this.getFolderPath("ResponseFolder") + servletType + "\\",
					this.getFolderPath("ResponseFolder") };
			FileUtil.createFolders(folders);
			/**
			 * Get the writer to write the response messages
			 */
			PrintWriter writer = response.getWriter();
			Map<String, String> map = new HashMap<String, String>();
			map.put("url", servletType);
			// processLogger(timeStamp, "");
			try {
				// Validate the root folder exist or not.
				File file = new File(this.getServletContext().getInitParameter(
						"RootPath"));
				String namespace = this.getServletContext().getInitParameter(
						"CitNamespace");
				StringBuilder builder = new StringBuilder();
				String responseText = "";

				if (file.exists() && file.isDirectory() && file.canWrite()) {
					InputStream in = request.getInputStream();
					String requestData = sService.getRequestData(in);
					//System.out.println(requestData);
					SOAPBody body = sService.getSOAPBody(requestData.trim());
					if (body == null) {
						builder.append(this.getServletContext()
								.getInitParameter("ERROR_REQUEST_FORMAT"));
						map.put("status", "error");
						// LOG:Logger Process
						processLogger(timeStamp, builder.toString());
						map.put("error_message", builder.toString());
						responseText = ResponseUtil.getObjectResponse(sService
								.initSOAPPart(namespace), map, namespace, null,
								null);
					} else {
						Document document = body.extractContentAsDocument();
						String rootName = document.getDocumentElement()
								.getNodeName();

						String configFileFolder = this
								.getFolderPath("RequestRulesFolder");// ConfigUtil.loadConfigPath(configFilePath);

						// Element root = document.getDocumentElement();
						/**
						 * objName is the configuration xml file's name
						 */
						String contextName = this.getServletContext()
								.getInitParameter("ContextName");
						String objName = FileUtil.getObjectName(rootName,
								contextName, servletType);
						String respFile = "";

						String respObjName = FileUtil.getRespObjectName(
								rootName, contextName, servletType);

						Document respRuleDoc = FileUtil.readValidateConfig(this
								.getFolderPath("ResponseRulesFolder")
								+ "/" + respObjName + ".xml");
						map.put("action", rootName);
						File configFolder = new File(configFileFolder);
						if (configFolder.exists() && configFolder.isDirectory()) {
							Document validateDoc = FileUtil
									.readValidateConfig(configFolder
											.getAbsolutePath()
											+ "/" + objName + ".xml");

							if (validateDoc == null || respRuleDoc == null) {
								respFile = "E_ConfigFileMiss";
								if (validateDoc == null) {
									builder
											.append(this
													.getServletContext()
													.getInitParameter(
															"ERROR_REQUEST_RULE")
													.replace(
															"##",
															this
																	.getFolderPath("RequestRulesFolder")
																	+ objName
																	+ ".xml"));
									map.put("status", "error");
									map
											.put("error_message", builder
													.toString());
									// LOG:Logger Process
									processLogger(timeStamp, builder.toString());
									responseText = ResponseUtil
											.getObjectResponse(sService
													.initSOAPPart(namespace),
													map, namespace, null,
													document);
								} else {
									if (respRuleDoc == null) {
										builder
												.append(this
														.getServletContext()
														.getInitParameter(
																"ERROR_RESPONSE_RULE")
														.replace(
																"##",
																this
																		.getFolderPath("ResponseRulesFolder")
																		+ respObjName
																		+ ".xml"));
										map.put("status", "error");
										map.put("error_message", builder
												.toString());
										// Create the response message
										responseText = ResponseUtil
												.getObjectResponse(
														sService
																.initSOAPPart(namespace),
														map, namespace, null,
														document);
									} else {
										map.put("status", "error");
										map.put("error_message", builder
												.toString());

										responseText = ResponseUtil
												.getObjectResponse(
														sService
																.initSOAPPart(namespace),
														map, namespace,
														respRuleDoc, document);
									}
								}
							} else {
								boolean result = vService.validateRequired(
										document, validateDoc, builder);
								if (result) {
									respFile = "Success";
									String fileName = FileUtil.getOutFileName(
											rootName, contextName, servletType,
											timeStamp);
									Document targetDocument = sService
											.convertRoot(document, namespace,
													contextName, servletType);
									boolean isRawOutput = Boolean
											.parseBoolean(this
													.getServletContext()
													.getInitParameter(
															"IsRawOutput"));
									if (isRawOutput) {

										sService
												.saveDoc(
														targetDocument,
														this
																.getFolderPath("RawSoapFolder")
																+ servletType
																+ "\\"
																+ fileName,
														true);
									}

									Document resultDocument = sService
											.noW3cDoc(targetDocument, namespace);

									sService.saveDoc(resultDocument, this
											.getFolderPath("XMLOutputFolder")
											+ servletType + "\\" + fileName,
											false);
									// Validation that if the create proces

									File outputFile = new File(this
											.getFolderPath("XMLOutputFolder")
											+ servletType + "\\" + fileName);
									if (outputFile.exists()) {
										// Because the response text will not
										// output, so the builer can be empty
										map.put("status", "accepted");
										map.put("error_message", builder
												.toString());
										responseText = ResponseUtil
												.getObjectResponse(
														sService
																.initSOAPPart(namespace),
														map, namespace,
														respRuleDoc, document);
									} else {
										respFile = "Failure";
										builder.append(this.getServletContext()
												.getInitParameter(
														"ERROR_CREATE"));
										map.put("status", "error");
										map.put("error_message", builder
												.toString());
										// LOG:Logger Process
										processLogger(timeStamp, builder
												.toString());
										responseText = ResponseUtil
												.getObjectResponse(
														sService
																.initSOAPPart(namespace),
														map, namespace,
														respRuleDoc, document);
									}
								} else {
									respFile = "Failure";
									String validation = new String(builder);
									builder = new StringBuilder();
									builder.append(this.getServletContext()
											.getInitParameter(
													"ERROR_VALIDATION")
											.replace("##", validation));
									map.put("status", "error");
									map
											.put("error_message", builder
													.toString());
									// Validate
									processLogger(timeStamp, builder.toString());
									responseText = ResponseUtil
											.getObjectResponse(sService
													.initSOAPPart(namespace),
													map, namespace,
													respRuleDoc, document);
								}
							}
						} else {
							map.put("status", "error");
							map.put("error_message", builder.toString());
							responseText = ResponseUtil.getObjectResponse(
									sService.initSOAPPart(namespace), map,
									namespace, respRuleDoc, document);
						}
						/**
						 * Open the debug model and check if the web application
						 * output the debug information
						 */
						// Response file name
						StringBuilder respBuilder = new StringBuilder();
						respBuilder.append(contextName).append("_").append(
								servletType).append("_").append(rootName)
								.append("_");
						DateFormat format = new SimpleDateFormat(
								"yyyyMMddHHmmssSSS");
						respBuilder.append(format.format(timeStamp)).append(
								".xml");

						boolean isSuccess = Boolean.parseBoolean(this
								.getServletContext().getInitParameter(
										"IsSuccessOutput"));
						if (isSuccess && respFile.equals("Success")) {
							Document respDoc = sService
									.stringToDoc(responseText);

							sService.saveDoc(respDoc, this
									.getFolderPath("ResponseFolder")
									+ servletType
									+ "\\"
									+ "Success"
									+ "_"
									+ respBuilder.toString(), false);
						}
						boolean isFailure = Boolean.parseBoolean(this
								.getServletContext().getInitParameter(
										"IsSuccessOutput"));
						if (isFailure && !respFile.equals("Success")) {
							Document respDoc = sService
									.stringToDoc(responseText);
							sService.saveDoc(respDoc, this
									.getFolderPath("ResponseFolder")
									+ servletType
									+ "\\"
									+ "Failure"
									+ "_"
									+ respBuilder.toString(), false);
						}
					}
				} else {
					builder.append(this.getServletContext().getInitParameter(
							"ERROR_ROOTPATH"));
					map.put("status", "error");
					map.put("error_message", builder.toString());
					responseText = ResponseUtil.getObjectResponse(sService
							.initSOAPPart(namespace), map, namespace, null,
							null);
				}
				// processLogger(timeStamp, builder.toString());
				writer.write(responseText);
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				writer.flush();
				writer.close();
			}
		} else {
			PrintWriter writer = response.getWriter();
			try {
				String responseText = "";
				Map<String, String> map = new HashMap<String, String>();
				StringBuilder builder = new StringBuilder();
				String namespace = this.getServletContext().getInitParameter(
						"CitNamespace");
				builder.append(this.getServletContext().getInitParameter(
						"ERROR_ROOTPATH"));
				map.put("status", "error");
				map.put("error_message", builder.toString());
				responseText = ResponseUtil.getObjectResponse(sService
						.initSOAPPart(namespace), map, namespace, null, null);
				writer.write(responseText);
			} catch (Exception ex) {

			} finally {
				writer.flush();
				writer.close();
			}
		}
	}
}
